﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Isuka.Iteration;
using Isuka.Spiritual;

namespace Isuka.Samples.Spiritual.FizzBuzz
{
    class Program
    {
        class FizzBuzz : Grammer<int, List<string>>
        {
            public FizzBuzz()
            {
                var fizz = If(x => x % 3 == 0);
                var buzz = If(x => x % 5 == 0);
                var fizzbuzz = fizz & buzz;
                var other = Any;

                Rule =
                     ( fizzbuzz[list => list.Add("FizzBuzz")]
                     | fizz[list => list.Add("Fizz")]
                     | buzz[list => list.Add("Buzz")]
                     | other[(list, x) => list.Add(x.ToString())]
                     )
                     .OneOrMore()
                     ;
            }
        }

        static List<string> Run(string name, Func<int[], List<string>> action)
        {
            var src = Enumerable.Range(1, 1000000).ToArray();
            Console.WriteLine("{0}-------", name);

            var stw = Stopwatch.StartNew();
            var result = action(src);
            stw.Stop();
            Console.WriteLine("{0} : {1}ms", name, stw.ElapsedMilliseconds);
            return result;
        }

        static void Main(string[] args)
        {
            var loopResult = Run("Loop", src =>
            {
                var result = new List<string>(src.Length);
                for (var i = 0; i < src.Length; i++)
                {
                    var x = src[i];
                    result.Add(x % 15 == 0 ? "FizzBuzz"
                             : (x % 3 == 0 ? "Fizz"
                             : (x % 5 == 0 ? "Buzz"
                             : x.ToString())));
                }
                return result;
            });

            var linqResult = Run("Linq", src => src.Select(
                                    x => x % 15 == 0 ? "FizzBuzz"
                                         : (x % 3 == 0 ? "Fizz"
                                         : (x % 5 == 0 ? "Buzz"
                                         : x.ToString()))).ToList());

            var fizzBuzz = new FizzBuzz();
            var sprtResult = Run("Spiritual", src =>
            {
                var result = new List<string>(src.Length);
                fizzBuzz.Run(src.AsIterable(), result);
                return result;
            });

            Console.WriteLine(loopResult.SequenceEqual(linqResult));
            Console.WriteLine(linqResult.SequenceEqual(sprtResult));

        }
    }
}
